#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <iostream>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include "logger.h"

using namespace std;
const char *LogLevelName[8] =
{
    "EMERGENCY",
    "ALERT",
    "CRITICAL",
    "ERROR",
    "WARNING",
    "NOTICE",
    "INFO",
    "DEBUG"
} ;
Logger *Logger::InstanceM = NULL;

Logger::Logger():
CurrentLogLine(0),
MaxLogLine(30000),
ComponentNameM("dataReport"),
LogFileNameM("/mnt/usr/log/dataReport.log"),
InitializedM(false),
ShouldLogToScreen(true),
ShouldLogToFile(true),
RollOverLogM(false),
pidM((uint32_t) getpid())
{
    memset(CountLog, 0, sizeof(CountLog));
    memset(OriginalLogMessage, 0, LogBufferLengthM);
    pthread_mutex_init(&counter_mutex, NULL);
};


bool Logger::initialize()
{

    if (ShouldLogToFile)
    {
        int32_t statRc;
        struct stat logStat;
        do
        {
            errno = 0;
            statRc = stat(LogFileNameM.c_str(), &logStat);
        } while ( (statRc == -1) && (errno == EINTR) );
        CurrentLogLine = 0;
        if ( statRc != -1 )
        {
            CurrentLogLine = logStat.st_size/100;
            RollOverLog();
        }
        else
        {
            LogStream.open(LogFileNameM.c_str(), ios::app);
        }
    }
    InitializedM = true;
    return true;
    
}

bool Logger::unintialize()
{
    fflush(stdout);
    fflush(stderr);
    LogStream.close();
    return true;
}

bool Logger::SetLogLevel(int32_t log_Level)
{
    LogLevel = log_Level;
    return true;
}

bool Logger::RollOverLog()
{
    LogStream << "rolling over log ..." << endl << flush;
    CurrentLogLine = 0;
    LogStream.close();
    
    string LastLogFileName(LogFileNameM);
    LastLogFileName += ".last";
    
    remove(LastLogFileName.c_str());
    rename(LogFileNameM.c_str(), LastLogFileName.c_str());
    
    LogStream.open(LogFileNameM.c_str(), ios::app);
    while((dup2(STDOUT_FILENO, STDERR_FILENO) == -1) && (errno== EINTR))
    {
    };
    return true;
   
}

void Logger::LogToStdout(const char* filename, uint32_t lineNumber, const int32_t logLevel, const char *const originalLogMessage)
{
    const int32_t timeBufferSize = 64;
    char timeBuffer[timeBufferSize];
    
    time_t currentTime;
    time(&currentTime);
    strftime(timeBuffer, timeBufferSize, "%Y/%m/%d %Z %H:%M:%S", localtime(&currentTime));
    cout << timeBuffer;
    cout << " " << ComponentNameM;
    cout << "[" << pidM << "]";
    cout << " " << LogLevelName[logLevel] << " ";
    cout << MessageCouter;
    cout << " " << filename << ":" << lineNumber;
    cout << " " << originalLogMessage;
    cout << endl <<flush; 

}

void Logger::LogToStream(const char* filename, uint32_t lineNumber, const int32_t logLevel, const char *const originalLogMessage)
{
    if ( CurrentLogLine >= MaxLogLine)
    {
        RollOverLog();
    }
    else
    {
        CurrentLogLine++;
    }
    const int32_t timeBufferSize = 64;
    char timeBuffer[timeBufferSize];
    
    time_t currentTime;
    time(&currentTime);
    strftime(timeBuffer, timeBufferSize, "%Y/%m/%d %Z %H:%M:%S", localtime(&currentTime));
    ostringstream logString;
    logString << timeBuffer;
    logString << " " << ComponentNameM;
    logString << "[" << pidM << "]";
    logString << " " << LogLevelName[logLevel] << " ";
    logString << MessageCouter;
    logString << " " << filename << ":" << lineNumber;
    logString << " " << originalLogMessage;
    logString << endl; 
    LogStream << logString.str() << flush;
}


void Logger::LogMessage(const char* filename, uint32_t lineNumber, const int32_t logLevel, const char *const originalLogMessage)
{

    if ( ShouldLogToFile )
    {
        LogToStream(filename,lineNumber, logLevel, originalLogMessage);

    }
    
    if ( ShouldLogToScreen )
    {
        LogToStdout(filename,lineNumber, logLevel, originalLogMessage);
    }
    MessageCouter++;

}





